//
// Created by WenYF on 2016/11/2.
//
// ifserver服务器包解析


#include "parser.h"

typedef struct ifparser_struct {
    void* queue;
    void* byteBuffer;
    BOOL findHead;
    void *dataSizeCollector;
    int dataSize;
    int readPosition;
	byte key;
} ifparser;

#define HEAD_LOW 0xDD
#define HEAD_HIGH 0xAA

// 512kb
#define BUFFER_SIZE (512 * 1024)

static BOOL parserHead(ifparser *p, void *buffer) {
    int oldPosition = if_buffer_position(buffer);
    int limit = if_buffer_limit(buffer);
    byte head[2];
    int i;
    for (i = oldPosition; i < limit - 1; i++) {
        head[0] = if_buffer_get(buffer);
        head[1] = if_buffer_get(buffer);
        if (head[0] == HEAD_HIGH && head[1] == HEAD_LOW) {
            if_buffer_setPosition(buffer, i+2);
            p->findHead = TRUE;
            return TRUE;
        }
    }

    return FALSE;
}

static BOOL parserDataSize(ifparser *p, void *buffer) {
    while (if_buffer_hasRemaining(buffer)) {
        if_buffer_put(p->dataSizeCollector, if_buffer_get(buffer));
        if (if_buffer_position(p->dataSizeCollector) == if_buffer_size(p->dataSizeCollector)) {
            if_buffer_flip(p->dataSizeCollector);
            p->dataSize = if_buffer_getInt(p->dataSizeCollector);
            if_buffer_clear(p->dataSizeCollector);
            return TRUE;
        }
    }

    return FALSE;
}

static void reset(ifparser *p) {
    if_buffer_clear(p->dataSizeCollector);
    if_buffer_clear(p->byteBuffer);
    p->findHead = FALSE;
    p->dataSize = -1;
    p->readPosition = 0;
}

static void parserData(ifparser *p) {
    int msgId = -1;
    short toSize = 0;
    byte *toBytes = NULL;
    short fromSize = 0;
    byte *fromBytes = NULL;
    void *byteBuffer = p->byteBuffer;
    byte type = -1;
	int value = -1;
	int crc  = -1;
	void *packet = NULL;
    logD("parser a incoming packet");

    // flip
    if_buffer_flip(byteBuffer);

    value = if_calculate_CRC32(if_buffer_array(byteBuffer), if_buffer_position(byteBuffer)
            , if_buffer_limit(byteBuffer) - 4);

    // crc 校验
    if_buffer_mark(byteBuffer);
    if_buffer_setPosition(byteBuffer, if_buffer_limit(byteBuffer) - 4);

    crc = if_buffer_getInt(byteBuffer);

    logD("value = %d, crc = %d", value, crc);

    if_buffer_rewind(byteBuffer);
    if (crc != value) {
        logW("A wrong packet, not crc.");
        reset(p);
        return;
    }

    if_buffer_setPosition(byteBuffer, 0);

	if_quick_decrypt_x(if_buffer_array(byteBuffer), if_buffer_position(byteBuffer)
			, if_buffer_limit(byteBuffer) - 4, p->key);
    
	if_buffer_printHex(byteBuffer);

    // msgid
    type = if_buffer_get(byteBuffer);
    msgId = if_buffer_getInt(byteBuffer);
    logD("parser id = %d", msgId);

    // to
    toSize = if_buffer_getShort(byteBuffer);
    logD("parser toSize = %d", toSize);
    if (toSize > 0) {
        toBytes = (byte *) malloc (sizeof(byte) * toSize);
        if_buffer_getBytes(byteBuffer, toBytes, toSize);
    }

    // from
    fromSize = if_buffer_getShort(byteBuffer);
    logD("parser fromSize = %d", fromSize);
    if (fromSize > 0) {
        fromBytes = (byte *) malloc (sizeof(byte) * fromSize);
        if_buffer_getBytes(byteBuffer, fromBytes, fromSize);
    } else {
        // 收到的包，必须要有from
        type = -1;
    }

    switch (type) {
        // 收到打开会话返回结果
        case PACKET_TYPE_SESSION_OPEN: {
            int dataSize = if_buffer_getInt(byteBuffer);
            if (dataSize >= 3) {
                byte sessionType = if_buffer_get(byteBuffer);
                // 初始化包
                ifsessionOpenPacket *sessionPacket = if_create_sessionOpen_packet(sessionType);

                dataSize = if_buffer_getShort(byteBuffer);
                logD("parser extra dataSize = %d", dataSize);
                if (dataSize > 0) {
                    byte *extra = (byte *) malloc (sizeof(byte) * (dataSize + 1));
                    if_buffer_getBytes(byteBuffer, extra, dataSize);
                    extra[dataSize] = '\0';
                    sessionPacket->extra = (char*)extra;
                }

                packet = sessionPacket;
            }
            break;
        }
        // 收到关闭会话
        case PACKET_TYPE_SESSION_CLOSE: {
            int dataSize = if_buffer_getInt(byteBuffer);
            logD("parser dataSize = %d", dataSize);
            if (dataSize >= 3) {
                byte sessionType = if_buffer_get(byteBuffer);
                ifsessionClosePacket *sessionPacket = if_create_sessionClose_packet(sessionType);

                dataSize = if_buffer_getShort(byteBuffer);
                logD("parser dataSize = %d", dataSize);

                if (dataSize > 0) {
                    byte *extra = (byte *) malloc (sizeof(byte) * (dataSize + 1));
                    if_buffer_getBytes(byteBuffer, extra, dataSize);
                    extra[dataSize] = '\0';
                    sessionPacket->extra = (char*)extra;
                }

                packet = sessionPacket;
            }
            break;
        }
        case PACKET_TYPE_MESSAGE: {
            int dataSize = if_buffer_getInt(byteBuffer);
            logD("parser dataSize = %d", dataSize);

            if (dataSize > 5) {
				byte *title = NULL;
				ifmessage *message = NULL;

                dataSize = if_buffer_get(byteBuffer);
                logD("parser title dataSize = %d", dataSize);

                if (dataSize > 0) {
                    title = (byte *) malloc (sizeof(byte) * (dataSize + 1));
                    if_buffer_getBytes(byteBuffer, title, dataSize);
                    title[dataSize] = '\0';
                }

                message = if_create_message((char*)title);

                if (if_buffer_remaining(byteBuffer) > 4) {
                    dataSize = if_buffer_getInt(byteBuffer);
                } else {
                    dataSize = 0;
                }
                logD("parser body dataSize = %d", dataSize);
                if (dataSize > 0) {
                    byte *body = (byte*) malloc (sizeof(byte) * (dataSize + 1));
                    if_buffer_getBytes(byteBuffer, body, dataSize);
                    body[dataSize] = '\0';
                    message->body = (char*)body;
                }

                packet = message;
            }

            break;
        }
        case PACKET_TYPE_EVENT: {
            int dataSize = if_buffer_getInt(byteBuffer);
            logD("parser dataSize = %d", dataSize);

            if (dataSize >= 7) {
                short eventType = if_buffer_getShort(byteBuffer);
                byte queryType = if_buffer_get(byteBuffer);
                int actionCode = if_buffer_getInt(byteBuffer);

                ifevent *event = if_create_event(eventType, queryType, actionCode);

                if (if_buffer_remaining(byteBuffer) > 4) {
                    dataSize = if_buffer_getInt(byteBuffer);
                } else {
                    dataSize = 0;
                }

                logD("parser event dataSize = %d", dataSize);

                if (dataSize > 0) {
                    byte *body = (byte*) malloc (sizeof(byte) * (dataSize + 1));
                    if_buffer_getBytes(byteBuffer, body, dataSize);
                    body[dataSize] = '\0';
                    event->body = (char*)body;
                }

                packet = event;
            }
            break;
        }
        default:
            break;
    }


    if (packet) {
        ifulaid *from = NULL;
        ifulaid *to = NULL;
        int id = -1;
		ifpacketWrapper *pw = NULL;

        if (fromBytes) {
            from = if_create_ulaid(fromBytes, fromSize);
            free(fromBytes);
        }

        if (toBytes) {
            to = if_create_ulaid(toBytes, toSize);
            free(toBytes);
        }

        if (msgId != -1) {
            id = msgId;
        }

        switch (type) {
            case PACKET_TYPE_SESSION_OPEN: {
                ifsessionOpenPacket *sessionPacket = (ifsessionOpenPacket*)packet;
                sessionPacket->from = from;
                sessionPacket->to = to;
                sessionPacket->id = id;
                break;
            }
            case PACKET_TYPE_SESSION_CLOSE: {
                ifsessionClosePacket *sessionPacket = (ifsessionClosePacket*)packet;
                sessionPacket->from = from;
                sessionPacket->to = to;
                sessionPacket->id = id;
                break;
            }
            case PACKET_TYPE_MESSAGE: {
                ifmessage *message = (ifmessage*)packet;
                message->from = from;
                message->to = to;
                message->id = id;
                break;
            }
            case PACKET_TYPE_EVENT: {
                ifevent *event = (ifevent*)packet;
                event->from = from;
                event->to = to;
                event->id = id;
                break;
            }
            default:
                break;
        }

        pw = (ifpacketWrapper*) malloc (sizeof(ifpacketWrapper));
        pw->type = type;
        pw->packet = packet;
        logD("add a packet to queue");
        if_queue_add(p->queue, pw);
    }

    reset(p);
}

// 初始化一个队列
void* if_parser_new(byte key) {
    ifparser *parser = (ifparser*) malloc (sizeof(ifparser));
    parser->queue = if_queue_new();
    parser->byteBuffer = if_buffer_new(BUFFER_SIZE);
    parser->dataSizeCollector = if_buffer_new(4);
	parser->key = key;
    reset(parser);

    return (void*)parser;
}

void if_parser_delete(void *parser) {
    if (!parser) {
        return;
    } else {
        ifparser *p = (ifparser*) parser;
        if_buffer_delete(p->byteBuffer);
        if_buffer_delete(p->dataSizeCollector);

        while (if_queue_length(p->queue) > 0) {
            ifpacketWrapper *pw = (ifpacketWrapper*) if_queue_poll(p->queue);
            if_delete_packet(pw);
        }

        if_queue_delete(p->queue);
        free (p);
    }
}


// 0没有，0x10 message， 0x20 event

void if_parser_read(void *parser, void *buffer) {
    logD("if_parser_read");
    if_buffer_printHex(buffer);
    if (!parser || !if_buffer_remaining(buffer)) {
        logD("buffer or parser is nil");
        return;
    } else {
        int i;
		int size = -1;
		BOOL done = FALSE;
        ifparser *p = (ifparser*) parser;

        logD("findHead = %d", p->findHead);
        if (p->findHead) {
            logD("datasize = %d", p->dataSize);
            if (p->dataSize == -1) {
                BOOL parserOk = parserDataSize(p, buffer);
                logD("parser buffer size ok = %d", parserOk);
                if (parserOk) {
                    return;
                } else {
                    if_parser_read(p, buffer);
                }
            } else {
                // do thing
            }
        } else {
            BOOL parserOk = parserHead(p, buffer);
            logD("parser head ok = %d", parserOk);
            logD("position = %d, limit = %d", if_buffer_position(buffer), if_buffer_limit(buffer));
            if (!parserOk) {
                return;
            } else {
                if_parser_read(p, buffer);
            }
        }

        if (p->dataSize == 0) {
            parserData(p);
            return;
        }

        if (!if_buffer_hasRemaining(buffer)) {
            return;
        }

        size = if_buffer_limit(buffer) - if_buffer_position(buffer);
        logD("buffer remain size = %d", size);
        logD("dataSize = %d, readPosition = %d", p->dataSize, p->readPosition);

        if (size >= p->dataSize - p->readPosition) {
            size = p->dataSize - p->readPosition;
            done = TRUE;
        }

        for (i = 0; i < size; i++) {
            if_buffer_put(p->byteBuffer, if_buffer_get(buffer));
            p->readPosition++;
        }

        if (done) {
            parserData(p);
            if_parser_read(p, buffer);
        } else {
            return;
        }
    }
}
BOOL if_parser_hasPacket(void *parser) {
    if (!parser) {
        return FALSE;
    } else {
        ifparser *p = (ifparser*) parser;
        int length = if_queue_length(p->queue);
        return length > 0 ? TRUE : FALSE;
    }

}

ifpacketWrapper* if_parser_getPacket(void *parser) {
    if (!parser) {
        return NULL;
    } else {
        ifparser *p = (ifparser*) parser;
        void *packet = if_queue_poll(p->queue);
        logD("poll packet addr = %d", packet);
        if (packet) {
            return (ifpacketWrapper*) packet;
        } else {
            return NULL;
        }
    }
}






